package com.zlsy.learning.leetcode.queue;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author zhouliang
 * @date 2020/8/14 10:33
 */
public class BlockQueue1 {

  private final Object addLock = new Object();
  private final Object deleteLock = new Object();
  private final Integer size = 30;
  private Object[] queue = new Object[size];
  private AtomicInteger count = new AtomicInteger(0);

  public void add(Object o) {
    // 获取生产锁,wait方法必须获取到对象锁后才可以调用，否则抛出异常
    synchronized (addLock) {

      // 判断是否超过队列大小,超过则进入等待
      while (count.get() >= size) {
        try {
          addLock.wait();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      // 存放一个
      queue[count.get()] = o;
      // 递增
      int i = count.incrementAndGet();
      // 打印一下日志
      String name = Thread.currentThread().getName();
      System.out.println(name + "生产了一个，现有数量" + i);
    }
    // 如果队列有数据，则调用notifyAll唤醒消费者
    if (count.get() >= 1) {
      // notifyAll、notify都需要先获取对象锁,否则会抛出异常
      synchronized (deleteLock) {
        deleteLock.notifyAll();
      }
    }
  }

  public Object poll() {
    Object o;
    // 先获取对象锁，和生产者类似
    synchronized (deleteLock) {
      // 队列里没有数据则等待
      while (count.get() <= 0) {
        try {
          deleteLock.wait();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      // 获取数据
      o = queue[count.get()];
      // 递减
      int i = count.decrementAndGet();
      String name = Thread.currentThread().getName();
      System.out.println(name + "消费了一个，现有数量" + i);
    }
    // 如果队列没有满，则可以唤醒生产者
    if (count.get() < size) {
      // 需要先获取到锁
      synchronized (addLock) {
        addLock.notifyAll();
      }
    }
    return o;
  }
}
